/**
 * Copyright (c) Martijn Grootens (m.e.grootens@student.utwente.nl), 
 * University of Twente.
 * Created july 2012.
 *
 * This file is part of dbcleaner.
 * 
 * dbcleaner is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * dbcleaner is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with dbcleaner.  If not, see <http://www.gnu.org/licenses/>.
 */

package dbcleaner.core.fix;

import java.io.*;
import java.util.*;
import dbcleaner.core.dbentries.*;
import dbcleaner.core.parse.*;
import dbcleaner.core.tags.*;
import dbcleaner.core.dbentries.*;
import dbcleaner.core.bibfields.*;

/**
 * Fixing the labels of the Entries.
 */
public class LabelFixer {
    
    /**
     * Create new labels for all DataBase Entries.
     */
    public static void fix_labels (DataBase db) {
        
        // Hold all present labels.
        ArrayList<String> label_store = new ArrayList<String>();
        
        // For each entry.
        for (Entry e : db.get_entries()) {
            
            // Fetcha new unique label for the Entry.
            String new_label = make_unique_label(e, label_store);
            
            // Set it.
            e.set_label(new_label);
            
            // Store the label to ensure further uniqueness
            label_store.add(new_label);
            
        }
        
        
    }
    
    /**
     * Make a unique label; it will differ from all labels in label_store.
     */
    private static String make_unique_label (Entry e, ArrayList<String> label_store) {
        
        // Fetch the base label, which will need to be made unique.
        String base_label = make_base_label(e);
        String final_label = base_label;
        
        // Append a number to a label when the base label already exists.
        int append = 0;
        
        while (!is_unique(base_label,label_store)) {
            
            // Create hopefully final label.
            final_label = base_label + "_" + (++append);
            
            // If indeed unique, return. Else increase counter.
            if (is_unique(final_label,label_store))
                return final_label;
            
        }
        
        return final_label;

    }
    
    /**
     * Make the base label, need not be unique.
     */
    private static String make_base_label (Entry e) {
        
        // Fetch author
        String author = e.get_field_contents("author");
        
        // For Entrys that have an editor INSTEAD of an author.
        if (author.equals(BibField.EMPTY))
            author = e.get_field_contents("editor");
        
        // fetch year and title
        String year = e.get_field_contents("year");
        String title = e.get_field_contents("title");
        
        // Build base label by extracting first words from author and title.
        String base_label = get_first_word(author) + " " + year + " " + get_first_word(title);
        
        // Replace spaces and other strange characters.
        for (int ii = 0; ii<base_label.length(); ++ii) {
            
            char ch = base_label.charAt(ii);
            
            if (!Character.isLetterOrDigit(ch) && !Character.isWhitespace(ch)) {
                base_label = base_label.substring(0,ii) + base_label.substring(ii+1);
                --ii;
            }
        }
        // Replace whitespace by underscores and make lower case.
        return base_label.replaceAll(" ", "_").toLowerCase();
        
    }
    
    /**
     * Check the uniqueness of a label; i.e. check if present in the list of labels.
     */
    private static boolean is_unique (String new_label, ArrayList<String> label_store) {
        
        for (String existing : label_store)
            if (existing.equals(new_label))
                return false;
        
        return true;
    }
    
    
    /**
     * Cut a String to the desired length.
     */
    private static String cut_string (String s, int l) {
        if (s.length()>l)
            return s.substring(0,l);
        return s;
    }
    
    /**
     * Extract first word from String. Split about space.
     */
    private static String get_first_word (String s) {
        if (s.indexOf(" ")>0)
            return s.split(" ")[0];
        else
            return s;
    }
    
}